process.env.NODE_ENV = 'development'

const chalk = require('chalk')
const fs = require('fs')
const path = require('path')
const rollup = require('rollup')

const { say } = require('cfonts')
const { spawn } = require('child_process')
const cowsay = require('cowsay')

const servceConfig = require('./rollup.config')
let servers = []
servers.push(servceConfig(process.env.NODE_ENV, { input: 'src/main.ts', output: 'dist/main.js' }))
const controllers = fs.readdirSync(path.resolve('./src/controllers'))
for (const controller of controllers) {
  servers.push(
    servceConfig(process.env.NODE_ENV, {
      input: `src/controllers/${controller}`,
      output: `dist/controllers/${controller.replace('.ts', '')}.js`
    })
  )
}

// console.log(controllers)

let serviceProcess = null
let manualRestart = false

function observer() {
  return new Promise((resolve, reject) => {
    const watcher = rollup.watch(servers)
    watcher.on('change', filename => {
      // 主进程日志部分
      logStats('服务端进程文件变更', filename)
    })
    watcher.on('event', event => {
      if (event.code === 'END') {
        if (serviceProcess && serviceProcess.kill) {
          manualRestart = true
          process.kill(serviceProcess.pid)
          serviceProcess = null
          startKoa()

          setTimeout(() => {
            manualRestart = false
          }, 5000)
        }

        resolve()
      } else if (event.code === 'ERROR') {
        reject(event.error)
      }
    })
  })
}

function startKoa() {
  let args = [path.join(__dirname, '../dist/main.js')]

  // detect yarn or npm and process commandline args accordingly
  if (process.env.npm_execpath.endsWith('yarn.js')) {
    args = args.concat(process.argv.slice(3))
  } else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
    args = args.concat(process.argv.slice(2))
  }

  serviceProcess = spawn('node', args)

  serviceProcess.stdout.on('data', data => {
    serviceLog(data, 'blue')
  })
  serviceProcess.stderr.on('data', data => {
    serviceLog(data, 'red')
    cowsayText(1)
  })

  serviceProcess.on('close', () => {
    if (!manualRestart) process.exit()
  })
}

async function init() {
  greeting()

  await observer()
    .then(startKoa)
    .catch(error => {
      cowsayText(true)
      process.exit(1)
    })

  cowsayText()
}

init()

function logStats(proc, data) {
  let log = ''

  log += chalk.yellow.bold(`┏ ${proc} ${new Array(19 - proc.length + 1).join('-')}`)
  log += '\n\n'

  if (typeof data === 'object') {
    data
      .toString({
        colors: true,
        chunks: false
      })
      .split(/\r?\n/)
      .forEach(line => {
        log += '  ' + line + '\n'
      })
  } else {
    log += `  ${data}\n`
  }

  log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
  console.log(log)
}

function serviceLog(data, color) {
  if (data) {
    let log = ''
    data = data.toString().split(/\r?\n/)
    data.forEach(line => {
      log += `  ${line}\n`
    })
    console.log(
      chalk[color].bold(`┏ 服务端日志 -------------------`) +
        '\n\n' +
        log +
        chalk[color].bold('┗ ----------------------------') +
        '\n'
    )
  }
}

function greeting() {
  const cols = process.stdout.columns
  let text = ''

  if (cols > 104) text = 'koa-node'
  else if (cols > 76) text = 'koa-|node'
  else text = false

  if (text) {
    say(text, {
      colors: ['yellow'],
      font: 'simple3d',
      space: false
    })
  } else console.log(chalk.yellow.bold('\n  koa-node'))
  console.log(chalk.blue('  准备启动...') + '\n')
}

function cowsayText(err = false) {
  const normal = cowsay.say({
    text: '装填完毕!,sir!',
    f: 'yasuna_06',
    wrap: false,
    wrapLength: 40
  })

  const error = cowsay.think({
    text: '啊咧?!有错误',
    f: 'yasuna_16',
    wrap: false,
    wrapLength: 40
  })

  const logsText = err ? chalk.red(error) : chalk.blue(normal)

  console.log(logsText)
}
